home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / mem.com / MEM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-24  |  12.8 KB  |  670 lines

  1. /*_ mem.c   Tue Mar  8 1988   Modified by: bright */
  2. /* $Header: mem.c,v 1.6 88/04/13 14:28:13 bright Locked $ */
  3. /* Memory management package                */
  4.  
  5. #if VAX11C
  6. #define  __FILE__  "mem.c"
  7. #endif
  8.  
  9. #include    <stdio.h>
  10.  
  11. #if __ZTC__
  12. #include    <stdlib.h>
  13. #include    <io.h>
  14. #else
  15. extern void *malloc();
  16. extern void *calloc();
  17. extern void *realloc();
  18. #endif
  19.  
  20. #ifndef MEM_H
  21. #include    "mem.h"
  22. #endif
  23.  
  24. #ifndef assert
  25. #include    <assert.h>
  26. #endif
  27.  
  28. #if MSC
  29. #include    <dos.h>
  30. #endif
  31.  
  32. #ifndef VAX11C
  33. #ifdef BSDUNIX
  34. #include <strings.h>
  35. #else
  36. #include <string.h>
  37. #endif
  38. #else
  39. extern char *strcpy(),*memcpy();
  40. extern int strlen();
  41. #endif  /* VAX11C */
  42.  
  43. int mem_inited = 0;        /* != 0 if initialized            */
  44.  
  45. static int mem_behavior = MEM_ABORTMSG;
  46. static int (*fp)(_0) = NULL;    /* out-of-memory handler    */
  47. static int mem_count;        /* # of allocs that haven't been free'd    */
  48.  
  49. /* Determine where to send error messages    */
  50. #if MSDOS
  51. #define ferr    stdout    /* stderr can't be redirected with MS-DOS    */
  52. #else
  53. #define ferr    stderr
  54. #endif
  55.  
  56. /*******************************/
  57.  
  58. void mem_setexception(flag,handler_fp)
  59. int flag;
  60. int (*handler_fp)(_0);
  61. {
  62.     mem_behavior = flag;
  63.     fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;
  64. #if MEM_DEBUG
  65.     assert(0 <= flag && flag <= MEM_RETRY);
  66. #endif
  67. }
  68.  
  69. /*************************
  70.  * This is called when we're out of memory.
  71.  * Returns:
  72.  *    1:    try again to allocate the memory
  73.  *    0:    give up and return NULL
  74.  */
  75.  
  76. static int near mem_exception()
  77. {   int behavior;
  78.  
  79.     behavior = mem_behavior;
  80.     while (1)
  81.     {
  82.     switch (behavior)
  83.     {
  84.         case MEM_ABORTMSG:
  85. #if MSDOS || __OS2__
  86.         /* Avoid linking in buffered I/O */
  87.         {    static char msg[] = "Fatal error: out of memory\r\n";
  88.  
  89.         write(1,msg,sizeof(msg) - 1);
  90.         }
  91. #else
  92.         fputs("Fatal error: out of memory\n",ferr);
  93. #endif
  94.         /* FALL-THROUGH */
  95.         case MEM_ABORT:
  96.         exit(EXIT_FAILURE);
  97.         /* NOTREACHED */
  98.         case MEM_CALLFP:
  99.         assert(fp);
  100.         behavior = (*fp)();
  101.         break;
  102.         case MEM_RETNULL:
  103.         return 0;
  104.         case MEM_RETRY:
  105.         return 1;
  106.         default:
  107.         assert(0);
  108.     }
  109.     }
  110. }
  111.  
  112. /****************************/
  113.  
  114. #if MEM_DEBUG
  115.  
  116. #undef mem_strdup
  117.  
  118. char *mem_strdup(s)
  119. const char *s;
  120. {
  121.     return mem_strdup_debug(s,__FILE__,__LINE__);
  122. }
  123.  
  124. char *mem_strdup_debug(s,file,line)
  125. const char *s;
  126. char *file;
  127. int line;
  128. {
  129.     char *p;
  130.  
  131.     p = s
  132.         ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
  133.         : NULL;
  134.     return p ? strcpy(p,s) : p;
  135. }
  136. #else
  137. char *mem_strdup(s)
  138. const char *s;
  139. {
  140.     char *p;
  141.  
  142.     p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL;
  143.     return p ? strcpy(p,s) : p;
  144. }
  145.  
  146. #endif /* MEM_DEBUG */
  147.  
  148. #ifdef MEM_DEBUG
  149.  
  150. static long mem_maxalloc;    /* max # of bytes allocated        */
  151. static long mem_numalloc;    /* current # of bytes allocated        */
  152.  
  153. #define BEFOREVAL    0x12345678    /* value to detect underrun    */
  154. #define AFTERVAL    0x87654321    /* value to detect overrun    */
  155.  
  156. #if SUN || SUN386
  157. static long afterval = AFTERVAL;    /* so we can do &afterval    */
  158. #endif
  159.  
  160. /* The following should be selected to give maximum probability that    */
  161. /* pointers loaded with these values will cause an obvious crash. On    */
  162. /* Unix machines, a large value will cause a segment fault.        */
  163. /* MALLOCVAL is the value to set malloc'd data to.            */
  164.  
  165. #if MSDOS || __OS2__
  166. #define BADVAL        0xFF
  167. #define MALLOCVAL    0xEE
  168. #else
  169. #define BADVAL        0x7A
  170. #define MALLOCVAL    0xEE
  171. #endif
  172.  
  173. /* Disable mapping macros    */
  174. #undef    mem_malloc
  175. #undef    mem_calloc
  176. #undef    mem_realloc
  177. #undef    mem_free
  178.  
  179. /* Create a list of all alloc'ed pointers, retaining info about where    */
  180. /* each alloc came from. This is a real memory and speed hog, but who    */
  181. /* cares when you've got obscure pointer bugs.                */
  182.  
  183. static struct mem_debug
  184. {    struct mh
  185.     { struct mem_debug *Mnext;    /* next in list            */
  186.       struct mem_debug *Mprev;    /* previous value in list    */
  187.       char *Mfile;        /* filename of where allocated        */
  188.       int Mline;        /* line number of where allocated    */
  189.       unsigned Mnbytes;    /* size of the allocation        */
  190.       long Mbeforeval;    /* detect underrun of data        */
  191.     } m;
  192.     char data[1];        /* the data actually allocated        */
  193. } mem_alloclist =
  194. {
  195.    {    (struct mem_debug *) NULL,
  196.     (struct mem_debug *) NULL,
  197.     "noname",
  198.     11111,
  199.     0,
  200.     BEFOREVAL
  201.    },
  202.    AFTERVAL
  203. };
  204.  
  205. /* Convert from a void *to a mem_debug struct.    */
  206. #define mem_ptrtodl(p)    ((struct mem_debug *) ((char *)p - sizeof(struct mh)))
  207.  
  208. /* Convert from a mem_debug struct to a mem_ptr.    */
  209. #define mem_dltoptr(dl)    ((void *) &((dl)->data[0]))
  210.  
  211. #define next        m.Mnext
  212. #define prev        m.Mprev
  213. #define file        m.Mfile
  214. #define line        m.Mline
  215. #define nbytes        m.Mnbytes
  216. #define beforeval    m.Mbeforeval
  217.  
  218. /*****************************
  219.  * Set new value of file,line
  220.  */
  221.  
  222. void mem_setnewfileline(ptr,fil,lin)
  223. void *ptr;
  224. char *fil;
  225. int lin;
  226. {
  227.     struct mem_debug *dl;
  228.  
  229.     dl = mem_ptrtodl(ptr);
  230.     dl->file = fil;
  231.     dl->line = lin;
  232. }
  233.  
  234. /****************************
  235.  * Print out struct mem_debug.
  236.  */
  237.  
  238. static void near mem_printdl(dl)
  239. struct mem_debug *dl;
  240. {
  241. #if LPTR
  242.     fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n",
  243.         dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));
  244. #else
  245.     fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%x\n",
  246.         dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));
  247. #endif
  248. }
  249.  
  250. /****************************
  251.  * Print out file and line number.
  252.  */
  253.  
  254. static void near mem_fillin(fil,lin)
  255. char *fil;
  256. int lin;
  257. {
  258.     fprintf(ferr,"File '%s' line %d\n",fil,lin);
  259.     fflush(ferr);
  260. }
  261.  
  262. /****************************
  263.  * If MEM_DEBUG is not on for some modules, these routines will get
  264.  * called.
  265.  */
  266.  
  267. void *mem_calloc(u)
  268. unsigned u;
  269. {
  270.          return mem_calloc_debug(u,__FILE__,__LINE__);
  271. }
  272.  
  273. void *mem_malloc(u)
  274. unsigned u;
  275. {
  276.          return mem_malloc_debug(u,__FILE__,__LINE__);
  277. }
  278.  
  279. void *mem_realloc(p,u)
  280. void *p;
  281. unsigned u;
  282. {
  283.          return mem_realloc_debug(p,u,__FILE__,__LINE__);
  284. }
  285.  
  286. void mem_free(p)
  287. void *p;
  288. {
  289.     mem_free_debug(p,__FILE__,__LINE__);
  290. }    
  291.  
  292.  
  293. /**************************/
  294.  
  295. void mem_freefp(p)
  296. void *p;
  297. {
  298.     mem_free(p);
  299. }
  300.  
  301. /***********************
  302.  * Debug versions of mem_calloc(), mem_free() and mem_realloc().
  303.  */
  304.  
  305. void *mem_malloc_debug(n,fil,lin)
  306. unsigned n;
  307. char *fil;
  308. int lin;
  309. {   void *p;
  310.  
  311.     p = mem_calloc_debug(n,fil,lin);
  312.     if (p)
  313.     memset(p,MALLOCVAL,n);
  314.     return p;
  315. }
  316.  
  317. void *mem_calloc_debug(n,fil,lin)
  318. unsigned n;
  319. char *fil;
  320. int lin;
  321. {
  322.     struct mem_debug *dl;
  323.  
  324.     do
  325.     dl = (struct mem_debug *)
  326.         calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1);
  327.     while (dl == NULL && mem_exception());
  328.     if (dl == NULL)
  329.     {
  330. #if 0
  331.     printf("Insufficient memory for alloc of %d at ",n);
  332.     mem_fillin(fil,lin);
  333.     printf("Max allocated was: %ld\n",mem_maxalloc);
  334. #endif
  335.     return NULL;
  336.     }
  337.     dl->file = fil;
  338.     dl->line = lin;
  339.     dl->nbytes = n;
  340.     dl->beforeval = BEFOREVAL;
  341. #if SUN || SUN386 /* bus error if we store a long at an odd address */
  342.     memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
  343. #else
  344.     *(long *) &(dl->data[n]) = AFTERVAL;
  345. #endif
  346.  
  347.     /* Add dl to start of allocation list    */
  348.     dl->next = mem_alloclist.next;
  349.     dl->prev = &mem_alloclist;
  350.     mem_alloclist.next = dl;
  351.     if (dl->next != NULL)
  352.     dl->next->prev = dl;
  353.  
  354.     mem_count++;
  355.     mem_numalloc += n;
  356.     if (mem_numalloc > mem_maxalloc)
  357.     mem_maxalloc = mem_numalloc;
  358.     return mem_dltoptr(dl);
  359. }
  360.  
  361. void mem_free_debug(ptr,fil,lin)
  362. void *ptr;
  363. char *fil;
  364. int lin;
  365. {
  366.     struct mem_debug *dl;
  367.  
  368.     if (ptr == NULL)
  369.         return;
  370. #if 0
  371.     {    fprintf(ferr,"Freeing NULL pointer at ");
  372.         goto err;
  373.     }
  374. #endif
  375.     if (mem_count <= 0)
  376.     {    fprintf(ferr,"More frees than allocs at ");
  377.         goto err;
  378.     }
  379.     dl = mem_ptrtodl(ptr);
  380.     if (dl->beforeval != BEFOREVAL)
  381.     {
  382. #if LPTR
  383.         fprintf(ferr,"Pointer x%lx underrun\n",ptr);
  384. #else
  385.         fprintf(ferr,"Pointer x%x underrun\n",ptr);
  386. #endif
  387.         goto err2;
  388.     }
  389. #if SUN || SUN386 /* Bus error if we read a long from an odd address    */
  390.     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
  391. #else
  392.     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
  393. #endif
  394.     {
  395. #if LPTR
  396.         fprintf(ferr,"Pointer x%lx overrun\n",ptr);
  397. #else
  398.         fprintf(ferr,"Pointer x%x overrun\n",ptr);
  399. #endif
  400.         goto err2;
  401.     }
  402.     mem_numalloc -= dl->nbytes;
  403.     if (mem_numalloc < 0)
  404.     {    fprintf(ferr,"error: mem_numalloc = %ld, dl->nbytes = %d\n",
  405.             mem_numalloc,dl->nbytes);
  406.         goto err2;
  407.     }
  408.  
  409.     /* Remove dl from linked list    */
  410.     if (dl->prev)
  411.         dl->prev->next = dl->next;
  412.     if (dl->next)
  413.         dl->next->prev = dl->prev;
  414.  
  415.     /* Stomp on the freed storage to help detect references    */
  416.     /* after the storage was freed.                */
  417.     memset((void *) dl,BADVAL,sizeof(*dl) + dl->nbytes);
  418.     mem_count--;
  419.  
  420.     /* Some compilers can detect errors in the heap.    */
  421. #if DLC
  422.     {    int i;
  423.         i = free(dl);
  424.         assert(i == 0);
  425.     }
  426. #else
  427.     free((void *) dl);
  428. #endif
  429.     return;
  430.  
  431. err2:
  432.     mem_printdl(dl);
  433. err:
  434.     fprintf(ferr,"free'd from ");
  435.     mem_fillin(fil,lin);
  436.     assert(0);
  437.     /* NOTREACHED */
  438. }
  439.  
  440. /*******************
  441.  * Debug version of mem_realloc().
  442.  */
  443.  
  444. void *mem_realloc_debug(oldp,n,fil,lin)
  445. void *oldp;
  446. unsigned n;
  447. char *fil;
  448. int lin;
  449. {   void *p;
  450.     struct mem_debug *dl;
  451.  
  452.     if (n == 0)
  453.     {    mem_free_debug(oldp,fil,lin);
  454.     p = NULL;
  455.     }
  456.     else if (oldp == NULL)
  457.     p = mem_malloc_debug(n,fil,lin);
  458.     else
  459.     {
  460.     p = mem_malloc_debug(n,fil,lin);
  461.     if (p != NULL)
  462.     {
  463.         dl = mem_ptrtodl(oldp);
  464.         if (dl->nbytes < n)
  465.         n = dl->nbytes;
  466.         memcpy(p,oldp,n);
  467.         mem_free_debug(oldp,fil,lin);
  468.     }
  469.     }
  470.     return p;
  471. }
  472.  
  473. /***************************/
  474.  
  475. void mem_check(_0)
  476. {   register struct mem_debug *dl;
  477.  
  478.     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
  479.     mem_checkptr(mem_dltoptr(dl));
  480. }
  481.  
  482. /***************************/
  483.  
  484. void mem_checkptr(p)
  485. register void *p;
  486. {   register struct mem_debug *dl;
  487.  
  488.     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
  489.     {
  490.     if (p >= (void *) &(dl->data[0]) &&
  491.         p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->nbytes))
  492.         goto L1;
  493.     }
  494.     assert(0);
  495.  
  496. L1:
  497.     dl = mem_ptrtodl(p);
  498.     if (dl->beforeval != BEFOREVAL)
  499.     {
  500. #if LPTR
  501.         fprintf(ferr,"Pointer x%lx underrun\n",p);
  502. #else
  503.         fprintf(ferr,"Pointer x%x underrun\n",p);
  504. #endif
  505.         goto err2;
  506.     }
  507. #if SUN || SUN386 /* Bus error if we read a long from an odd address    */
  508.     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
  509. #else
  510.     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
  511. #endif
  512.     {
  513. #if LPTR
  514.         fprintf(ferr,"Pointer x%lx overrun\n",p);
  515. #else
  516.         fprintf(ferr,"Pointer x%x overrun\n",p);
  517. #endif
  518.         goto err2;
  519.     }
  520.     return;
  521.  
  522. err2:
  523.     mem_printdl(dl);
  524.     assert(0);
  525. }
  526.  
  527. #else
  528.  
  529. /***************************/
  530.  
  531. void *mem_malloc(numbytes)
  532. unsigned numbytes;
  533. {    void *p;
  534.  
  535.     if (numbytes == 0)
  536.         return NULL;
  537.     while (1)
  538.     {
  539.         p = malloc(numbytes);
  540.         if (p == NULL)
  541.         {    if (mem_exception())
  542.                 continue;
  543.         }
  544.         else
  545.             mem_count++;
  546.         break;
  547.     }
  548.     /*printf("malloc(%d) = x%lx\n",numbytes,p);*/
  549.     return p;
  550. }
  551.  
  552. /***************************/
  553.  
  554. void *mem_calloc(numbytes)
  555. unsigned numbytes;
  556. {    void *p;
  557.  
  558.     if (numbytes == 0)
  559.         return NULL;
  560.     while (1)
  561.     {
  562.         p = calloc(numbytes,1);
  563.         if (p == NULL)
  564.         {    if (mem_exception())
  565.                 continue;
  566.         }
  567.         else
  568.             mem_count++;
  569.         break;
  570.     }
  571.     /*printf("calloc(%d) = x%lx\n",numbytes,p);*/
  572.     return p;
  573. }
  574.  
  575. /***************************/
  576.  
  577. void *mem_realloc(oldmem_ptr,newnumbytes)
  578. void *oldmem_ptr;
  579. unsigned newnumbytes;
  580. {   void *p;
  581.  
  582.     if (oldmem_ptr == NULL)
  583.     p = mem_malloc(newnumbytes);
  584.     else if (newnumbytes == 0)
  585.     {    mem_free(oldmem_ptr);
  586.     p = NULL;
  587.     }
  588.     else
  589.     {
  590.     do
  591.         p = realloc(oldmem_ptr,newnumbytes);
  592.     while (p == NULL && mem_exception());
  593.     }
  594.     /*printf("realloc(x%lx,%d) = x%lx\n",oldmem_ptr,newnumbytes,p);*/
  595.     return p;
  596. }
  597.  
  598. /***************************/
  599.  
  600. void mem_free(ptr)
  601. void *ptr;
  602. {
  603.     /*printf("free(x%lx)\n",ptr);*/
  604.     if (ptr != NULL)
  605.     {    assert(mem_count > 0);
  606.     mem_count--;
  607. #if DLC
  608.     {    int i;
  609.  
  610.         i = free(ptr);
  611.         assert(i == 0);
  612.     }
  613. #else
  614.     free(ptr);
  615. #endif
  616.     }
  617. }
  618.  
  619. #endif /* MEM_DEBUG */
  620.  
  621. /***************************/
  622.  
  623. void mem_init()
  624. {
  625.     if (mem_inited == 0)
  626.     {    mem_count = 0;
  627. #if MEM_DEBUG
  628.         mem_numalloc = 0;
  629.         mem_maxalloc = 0;
  630.         mem_alloclist.next = NULL;
  631. #endif
  632.         mem_inited++;
  633.     }
  634. }
  635.  
  636. /***************************/
  637.  
  638. void mem_term()
  639. {
  640.  
  641.     if (mem_inited)
  642.     {
  643. #if MEM_DEBUG
  644.         register struct mem_debug *dl;
  645.  
  646.         for (dl = mem_alloclist.next; dl; dl = dl->next)
  647.         {    fprintf(ferr,"Unfreed pointer: ");
  648.             mem_printdl(dl);
  649.         }
  650. #if 0
  651.         fprintf(ferr,"Max amount ever allocated == %ld bytes\n",
  652.             mem_maxalloc);
  653. #endif
  654. #else
  655.         if (mem_count)
  656.             fprintf(ferr,"%d unfreed items\n",mem_count);
  657. #endif /* MEM_DEBUG */
  658.         assert(mem_count == 0);
  659.         mem_inited = 0;
  660.     }
  661. }
  662.  
  663. #undef next
  664. #undef prev
  665. #undef file
  666. #undef line
  667. #undef nbytes
  668. #undef beforeval
  669.  
  670.